﻿using System;

namespace paiban
{
    using NPOI.SS.Formula.Functions;
    using paiban.data;
    using xlstool;

    internal class D001
    {
        WorkPersonInfo info { get; set; }
        string[] extra_personmap;
        int[] extra_nummap;
        int[] extra_pos;
        string[] table;
        string[] b_ext;
        int[] b_day;
        int[] b_num;
        int[] b_type;
        int[] b_pos;
        int b_size;
        int table_size;
        string[] extra_allname;
        public D001(WorkPersonInfo info)
        {
            this.info = info;
            extra_personmap = cgsys.config.Array("附加功能人员表");
            extra_nummap = new int[extra_personmap.Length];
            extra_pos = new int[extra_personmap.Length];
            var num_texts = cgsys.config.Array("附加功能对应数量");
            int pos = 0;
            for (var i = 0; i < num_texts.Length; i++)
            {
                extra_pos[i] = pos;
                pos += extra_nummap[i] = int.Parse(num_texts[i]);
            }
            extra_allname = cgsys.config.Array("附加功能完整表");

            init_bs();
            init_table();

        }
        public int read_num(string person)
        {
            var ix = Array.IndexOf(extra_personmap, person);
            if (ix == -1) throw new ArgumentException();

            return extra_nummap[ix];
        }
        public string read_name(string person, int no)
        {
            var ix = Array.IndexOf(extra_personmap, person);
            if (ix == -1) throw new ArgumentException();

            return extra_allname[extra_pos[ix] + no];
        }
        public IEnumerable<string> LoopExtraPerson()
        {
            for (var i = 0; i < extra_personmap.Length; i++) yield return extra_personmap[i];
        }
        internal void init_bs()
        {
            // calc b size
            b_size = 0;
            foreach (var day in info.LoopDays())
            {
                var wan = info.ReadWanbanPerson(day);
                var not_wan = info.ReadNotWanbanPerson(day);
                
                foreach (var person in LoopExtraPerson())
                {
                    if (!wan.Contains(person)) b_size++;
                    if (!not_wan.Contains(person)) b_size++;
                }
            }

            b_ext = new string[b_size];
            b_day = new int[b_size];
            b_type = new int[b_size];
            b_num = new int[b_size];
            b_pos = new int[b_size];
            var i = 0;
            var pos = 0;
            foreach (var day in info.LoopDays())
            {
                var wan = info.ReadWanbanPerson(day);
                var not_wan = info.ReadNotWanbanPerson(day);

                foreach (var person in LoopExtraPerson())
                {
                    if (!wan.Contains(person))
                    {
                        b_type[i] = 1;
                        b_ext[i] = person;
                        b_day[i] = day;
                        b_pos[i] = pos;
                        pos += b_num[i] = read_num(person);

                        i++;
                    }
                    if (!not_wan.Contains(person))
                    {
                        b_type[i] = 0;
                        b_ext[i] = person;
                        b_day[i] = day;
                        b_pos[i] = pos;
                        pos += b_num[i] = read_num(person);

                        i++;
                    }
                }
            }

            table_size = 0;
            for(i = 0; i < b_size; i ++)  table_size += b_num[i];

        }
        internal void init_table()
        {
            table = new string[table_size];

            for(var bno = 0; bno < b_size; bno++)
            {
                var day = b_day[bno];
                var num = b_num[bno];
                var pos = b_pos[bno];
                var typ = b_type[bno];
                var ext_person = b_ext[bno];

                var ix = 0;
                while (ix < num)
                    foreach (var p in LoopWorkPerson(day, typ))
                    {
                        table[pos + ix] = p;
                        ix++;
                        if (ix >= num) break;
                    }
            }
        }

        public IEnumerable<string> LoopWorkPerson(int day, int type)
        {
            switch (type)
            {
                case 1:
                    foreach (var p in info.ReadWanbanPerson(day))
                        if (!extra_personmap.Contains(p)) yield return p;
                    break;
                case 0:
                    foreach (var p in info.ReadNotWanbanPerson(day))
                        if (!extra_personmap.Contains(p)) yield return p;
                    break;
                default: throw new ArgumentException();
            }
        }
        public void SaveExcel(string name)
        {
            var xls = new Excel2003File();
            FillExcelSheet(xls.GetWorkbook().ToSheet($"{info.year}年{info.month}月额外排班"));
            using (var f = File.Create($"./{name}.xls")) xls.ToStream(f);
        }
        public void FillExcelSheet(Excel2003Sheet pb)
        {
            var rowno = 1;
            var row = pb.ToRow(rowno);
            row.ToCell(1).SetValue("日期");
            row.ToCell(2).SetValue("(早/晚)班");
            row.ToCell(3).SetValue("分配给");

            row.ToCell(4).SetValue("店铺");
            row.ToCell(5).SetValue("来源");

            for (var bno = 0; bno < b_size; bno++)
            {
                var day = b_day[bno];
                var num = b_num[bno];
                var pos = b_pos[bno];
                var typ = b_type[bno];
                var ext_person = b_ext[bno];

                for (var no = 0; no < num; no++)
                {
                    rowno++;
                    row = pb.ToRow(rowno);
                    row.ToCell(1).SetValue($"{info.month}月{day}日");
                    row.ToCell(2).SetValue(typ == 1? $"晚":"早");
                    row.ToCell(3).SetValue(table[pos+no]);
                    row.ToCell(4).SetValue(read_name(ext_person, no));
                    row.ToCell(5).SetValue(ext_person);
                }
            }
        }
    }
}
